package com.qyxx.platform.common.utils.sevenziputils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
import net.sf.sevenzipjbinding.ArchiveFormat;
import net.sf.sevenzipjbinding.ExtractOperationResult;
import net.sf.sevenzipjbinding.ISequentialOutStream;
import net.sf.sevenzipjbinding.IInArchive;
import net.sf.sevenzipjbinding.SevenZip;
import net.sf.sevenzipjbinding.SevenZipException;
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
import net.sf.sevenzipjbinding.simple.ISimpleInArchive;
import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem;

/**
 * 
 * 
 * 
 * */

public class UnzipBigFile {
	private static  FileOutputStream fos; // 输出流

	/**
	 * 
	 * @param filepath
	 *            7z文件
	 * @param destinationDir
	 *            解压输出目标目录
	 * @param password
	 *            7z文件密码
	 */
	public static void extractile(String filepath, final String destinationDir) {
		RandomAccessFile randomAccessFile = null;
		IInArchive inArchive = null;
		try {
			randomAccessFile = new RandomAccessFile(filepath, "r"); // 只读模式
			inArchive = SevenZip.openInArchive(ArchiveFormat.ZIP, // 已7zip的文件形式开发
					new RandomAccessFileInStream(randomAccessFile)); // 2种模式一种有密码，一种无密码

			// 获得SimpleInArchive接口
			ISimpleInArchive simpleInArchive = inArchive.getSimpleInterface();

			for (final ISimpleInArchiveItem item : simpleInArchive.getArchiveItems()) {

				if (!item.isFolder()) {
					ExtractOperationResult result;
					// final long[] sizeArray = new long[1];

					// 判断是否存在目录
					String subdir = item.getPath();
					if (subdir.lastIndexOf("\\") > 0) {
						subdir = subdir.substring(0, subdir.lastIndexOf("\\"));
						File myfile = new File(destinationDir + subdir);
						if (!myfile.exists()) {
							myfile.mkdirs();
						}
						// System.out.println("创建文件夹"+destinationDir+subdir);
					}

					File file = new File(destinationDir + item.getPath());

					fos = new FileOutputStream(file);

					// 解压缩处理带密码的程序
					result = item.extractSlow(new ISequentialOutStream() {
						public int write(byte[] data) throws SevenZipException {
							/*
							 * 关键将byte[] 写入文件，由于大文件,byte[] 数组最大65535不能一次读完,将
							 * FileOutputStream到类中公用 一次读不完可以继续读，继续向目标输出流写
							 * 官方论坛有人问到这个问题,Boris Brodski 有这样的回答
							 * 
							 * https://sourceforge.net/p/sevenzipjbind/
							 * discussion/757964/thread/11e9d321/
							 * 
							 * Yes, you can do that. Simple process only 1K data
							 * and return 1024. Here is an example:
							 * 
							 * public int write(byte data) throws
							 * SevenZipException { int processedLength = 1024;
							 * if (data.length < 1024) { processedLength =
							 * data.length; } process(data, processedLength);
							 * 
							 * return processedLength; }
							 * 
							 * The unprocessed data will be delivered with the
							 * consequent write-method call.
							 */

							try {
								fos.write(data);
							} catch (IOException e) {

								e.printStackTrace();
							}

							return data.length;
						}
					} // 密码关键这里
					);

					if (result == ExtractOperationResult.OK) {
						fos.close(); // 写完才关闭输出流
						System.out.println();

					} else {
						System.err.println("Error extracting item: " + result);
					}

				} // if 结束
			} // for 循环

		} catch (Exception e) {
			System.err.println("Error occurs: " + e);
			e.printStackTrace();
			System.exit(1);
		} finally {
			if (inArchive != null) {
				try {
					inArchive.close();
				} catch (SevenZipException e) {
					System.err.println("Error closing archive: " + e);
				}
			}

			if (randomAccessFile != null) {
				try {
					randomAccessFile.close();
				} catch (IOException e) {
					System.err.println("Error closing file: " + e);
				}
			}

		}
	}

	public static void main(String[] str) {
		UnzipBigFile unzip = new UnzipBigFile();

		// 多文件及文件夹子嵌套解压缩
		unzip.extractile("G:/ceshi/config.jwp", "G:/ceshi/");



	}
}
